package web.dao;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;

/**
 * @author orlin
 *
 */
public class Query extends QueryPatternImpl {

	private Class<?> persistentClass;
	private String sql;
	private String tableName;
	private String nick;
	private Session session;

	public Query(String tableName, Class<?> persistentClass) {
		this(tableName, "x", persistentClass);
	}

	public Query(String tableName, String nick, Class<?> persistentClass) {
		this.persistentClass = persistentClass;
		this.tableName = tableName;
		setNickName(nick);
	}

	public Class<?> getPersistentClass() {
		return persistentClass;
	}

	public String getTableName() {
		return tableName;
	}

	@Override
	public String getNickName() {
		return nick;
	}

	public void setNickName(String nick) {
		this.nick = nick;
	}

	public <T> Collection<T> list() {
		Map<String,Object> parameters = getParameters();
		/** prepare sql */
		sql = getQueryText();
		//log.debug(sql);
		getSession();
		/** query parameters */
		for (Entry<String,Object> entry : parameters.entrySet()) {
			if (entry.getValue() instanceof Collection<?>) {
				/** list parameter */
				Collection<?> c = (Collection<?>) entry.getValue();
				setParameterList(entry.getKey(), c);
				/**/log.debug("param: " + entry.getKey() + " = " + entry.getValue());
			} else {
				/** plain parameter */
				/**/log.debug("param: " + entry.getKey() + " = " + entry.getValue());
				setParameter(entry.getKey(), entry.getValue());
			}
		}
		/** query */
		Collection<T> list = extract(sql);
		rollback();
		return list;
	}

	private String setParameterList(String key, Collection<?> values) {
		StringBuffer value = new StringBuffer();
		for (Object val: values) {
			if (value.length() != 0) {
				value.append(COMMA);
				value.append(SPACE);
			}
			value.append(val); 
		}
		sql = sql.replaceAll(COLUMN + key, QUOTE + values.toString() + QUOTE);
		return sql;
	}

	private String setParameter(String key, Object value) {
		sql = sql.replaceAll(COLUMN + key, QUOTE + value.toString() + QUOTE);
		return sql;
	}

	/**
	 * @return
	 */
	private Session getSession() {
		if (session == null) {
			BaseDAO dao = new BaseDAO();
			session = dao.getSession();
			session.beginTransaction();
		}
		return session;
	}
	
	/**
	 * @return
	 */
	private void rollback() {
		if (session == null) {
			BaseDAO dao = new BaseDAO();
			dao.getSession().rollbackTransaction();
		}
	}

	@SuppressWarnings("unchecked")
	private <T> Collection<T> extract(String sql) {
		return (Collection<T>) session.executeQuery(persistentClass, sql);
	}

	/**
	 * @return
	 */
	public Collection<String> getColumns() {
		Collection<String> columns = new ArrayList<String>();
//		Session session = getSession();
//		SessionFactory sessionFactory = session.getSessionFactory();
//		ClassMetadata metadata = sessionFactory.getClassMetadata(persistentClass);
//		String[] hibClassProps = metadata.getPropertyNames();
//		columns = new ArrayList<String>(Arrays.asList(hibClassProps));
//		if (metadata.hasIdentifierProperty()) {
//			columns.add(0,metadata.getIdentifierPropertyName());
//		}
		return columns;
	}

	@Override
	public String getSelectClause() {
		StringBuffer result = new StringBuffer();
		result.append(getNickColumns());
		String selectClause = super.getSelectClause();
		if ((null != selectClause) && (!selectClause.isEmpty())) {
			result.append(COMMA);
			result.append(selectClause);
		}
		return result.toString();
	}

	private String getNickColumns() {
		StringBuffer result = new StringBuffer();
		Collection<String> columns = getColumns();
		if (columns.size() > 0) {
			for (String column: columns) {
				if (result.length() > 0 ) {
					result.append(COMMA);
				}
				result.append(getNickName());
				result.append(DOT);
				result.append(column);
			}
		} else {
			// TODO fix dbu
			//result.append(getNickName());
			//result.append(DOT);
			result.append(STAR);
		}
		return result.toString();
	}

	@Override
	public String getFromClause() {
		StringBuffer result = new StringBuffer();
		result.append(getTableName());
		// TODO fix dbu
		//result.append(AS);
		//result.append(getNickName());
		String fromClause = super.getFromClause();
		if ((null != fromClause) && (!fromClause.isEmpty())) {
			result.append(COMMA);
			result.append(fromClause);
		}
		return result.toString();
	}
}
